import re
from math import exp



from src.param import ip6_regex
from mycluster.pearson import corrcoef

'''
数据结构：
tx_list：[ {"tx_id":'xxxxxx'
            "list":[  {"ip":'111.111.11.11',"timestamp":9239874},{},{} ]
            "weight":[0,0,0,0,0,0,,00,0,0,,0,00,,00,0,0,0,0]
            } , {}  ]
'''


def get_info_from_bcclient_log(log_file, output_file):
    """
    读取bcclient的日志文件，解析提取其中的交易数据包的信息，输出成文件 ，并返回两个列表
    :param log_file:日志文件
    :param output_file:输出结果文件
    :return: tx_list,交易列表，ip_list，全部节点ip
    """
    tx_list = []  # 存放交易的列表，每一项是一个字典
    ip_list = []  # 实验期间的全部ip peers

    # print("01 对bcclient的日志进行有效内容提取")
    with open(log_file, 'r', encoding='utf8') as fp, open(output_file, 'w', encoding='utf8') as wp:
        for line in fp.readlines():
            # if "r:itx:" in line: # 选择有交易数据信息的行
            if "r:itx:" in line:
                if len(line.split(' '))!=6: #格式不对，直接跳过
                    continue
                li = re.findall(r"(\b[0-9]{7,14}\b)", line)
                if len(li) == 0:
                    continue
                timestamp = li[0]

                li = re.findall(r"\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}.[0-9]{4,5}\.[0-9]\b", line)
                if len(li) == 0:
                    continue
                ip_addr = li[0]

                li = re.findall(r"\b[0-9,a-z]{64}", line)
                if len(li) == 0:
                    continue
                tx_id = li[0]

                res = tx_id + " " + timestamp + ' ' + ip_addr + '\n'
                wp.writelines(res)

                # 02 对提取的每一行，把它添加到一个交易列表中，并更新ip_list列表
                # 更新ip列表ip_list
                if ip_addr not in ip_list:
                    ip_list.append(ip_addr)
                # 更新交易列表tx_list
                flag = False  # 该笔交易是否已经存在，即被别的节点广播过
                for i in tx_list:
                    if i["tx_id"] == tx_id:
                        flag = True
                        has_send = False  # 有些交易消息可能被重复记录，做个判断，重复的直接跳过
                        for j in i["list"]:
                            if j["ip"] == ip_addr:  # 该消息包不是该节点第一次发送了，直接跳过
                                has_send = True
                        if has_send:
                            continue
                        i["list"].append({"timestamp": int(timestamp), "ip": ip_addr})

                if not flag:
                    tx_list.append({"tx_id": tx_id, "list": [{"timestamp": int(timestamp), "ip": ip_addr}]})

    return tx_list, ip_list
def get_delay(log_file,ip_list):

    ip_delay_list=[]
    for ip in ip_list:
        if ip=="18.159.243.26:18333.2":
            print("sdsdsd")
            pass
        with open(log_file, 'r', encoding='utf8') as fp:
            send_timestamp =0
            receive_timestamp=0
            for line in fp.readlines():
                #Jan 24 07:52:48.446 (518402821) [INFO]: Connecting to 108.59.197.192:18333.3 (try 1)
                if "Connecting to "+ip in line:
                    li = re.findall(r"\([0-9]{7,14}\)", line)
                    if len(li) == 0:
                        continue
                    send_timestamp = int(li[0][1:-1])

                #Version received. peer=104.248.2.30:18333.1
                if "peer="+ip in line:
                    #必须加括号
                    li = re.findall(r"\([0-9]{7,14}\)", line)
                    if len(li) == 0:
                        continue
                    receive_timestamp = int(li[0][1:-1])
                if send_timestamp!=0 and receive_timestamp!=0 and receive_timestamp>send_timestamp:
                    break
            ip_delay_list.append({"ip": ip, "delay": (receive_timestamp-send_timestamp)/2})

    return ip_delay_list



'''
数据结构：
tx_list：[ {"tx_id":'xxxxxx'
            "list":[  {"ip":'111.111.11.11',"timestamp":9239874},{},{} ]
            "weight":[0,0,0,0,0,0,,00,0,0,,0,00,,00,0,0,0,0]
            } , {}  ]
'''
def delete_min_tx(tx_list,min_num):
    count=0
    for tx in tx_list:
        tx["isCompute"]=True
        if len(tx["list"])<min_num:
            tx["isCompute"]=False
            count=count+1

    tx_list[:] = [d for d in tx_list if d.get("isCompute") == True]
    return count
def change_relative_timestamp1(tx_list):
    # print("03 对交易列表，把每个节点的转发由时间戳 改为 相对时间戳")
    for tx in tx_list:
        min_timestamp = 9999999999
        #更新接受时间戳为发送时间戳
        for ip in tx["list"]:
            if ip["timestamp"] < min_timestamp:
                min_timestamp = ip["timestamp"]
        for ip in tx['list']:
            ip["timestamp"] = ip["timestamp"] - min_timestamp

def change_relative_timestamp(tx_list,ip_delay):
    # print("03 对交易列表，把每个节点的转发由时间戳 改为 相对时间戳")
    for tx in tx_list:
        min_timestamp = 999999999999
        #更新接受时间戳为发送时间戳
        for ip in tx["list"]:
            index=find_ip_in_ip_delay(ip_delay,ip["ip"])
            ip["timestamp"]=ip["timestamp"]-ip_delay[index]["delay"]

        for ip in tx["list"]:
            if ip["timestamp"] < min_timestamp:
                min_timestamp = ip["timestamp"]
        for ip in tx['list']:
            ip["timestamp"] = ip["timestamp"] - min_timestamp


def find_ip_in_ip_delay(ip_delay,target_ip):
    for index,ip in enumerate(ip_delay):
        if ip["ip"]==target_ip:
            return index

'''
数据结构：
tx_list：[ {"tx_id":'xxxxxx'
            "list":[  {"ip":'111.111.11.11',"timestamp":9239874},{},{} ]
            "weight":[0,0,0,0,0,0,,00,0,0,,0,00,,00,0,0,0,0]
            } , {}  ]
'''


def compute_weight_vertor_Pro(tx_list, ip_list,N):
    """
        方法 ：遍历 tx_list列表，为每个tx字典追加件一项权重列表(模拟向量)
        改进：修改了权重考虑的方式，之前是计算完权重再考虑前N个，修改为直接考虑前N个，再计算权重
    """
    # print("04 求每个交易的权重向量,ip顺序以ip_list为准")
    for index_1,tx in enumerate(tx_list):
        if(index_1==134):
            print("aaaa")

        tx["weight"] = [0] * len(ip_list)  # 创建全0列表

        mid_timestamp = 0
        # 这里不太严谨，考虑按行读取时，应该也是按时间戳顺序的， 所以tx["list"]里面的时间戳应该是有序的，直接取中间的作为中位数，不行再算
        # print('该交易传播节点数：' + str(len(tx["list"])))
        if len(tx["list"])<N:
            if len(tx["list"]) % 2 == 1:
                mid_timestamp = tx["list"][len(tx["list"]) // 2]["timestamp"]
            else:
                mid_timestamp = (tx["list"][len(tx["list"]) // 2]["timestamp"] + tx["list"][len(tx["list"]) // 2 - 1][
                    "timestamp"]) / 2
        elif N % 2 == 1:
            mid_timestamp = tx["list"][N // 2]["timestamp"]
        else:
            mid_timestamp = (tx["list"][N // 2]["timestamp"] + tx["list"][N // 2 - 1][
                "timestamp"]) / 2
        k = mid_timestamp / 0.8325546111577  # 根号(-ln(0.5))
        ith = 0
        for node in tx["list"]:  # 这里的node其实就可以指一个数据包{ip，timestamp}
            if ith >= N:
                break
            index = ip_list.index(node['ip'])
            if k == 0:
                tx["weight"][index] = 1.0
            else:
                weight=exp(-(node["timestamp"] * 1.0 / k) ** 2)
                tx["weight"][index] = weight

            ith += 1
    # with open("data/res.json", 'w', encoding='utf8') as ft:
    #     ft.write(str(tx_list))

def compute_weight_vertor(tx_list, ip_list,N):
    """
        方法 ：遍历 tx_list列表，为每个tx字典追加件一项权重列表(模拟向量)

    """
    # print("04 求每个交易的权重向量,ip顺序以ip_list为准")
    for tx in tx_list:
        tx["weight"] = [0] * len(ip_list)  # 创建全0列表

        mid_timestamp = 0
        # 这里不太严谨，考虑按行读取时，应该也是按时间戳顺序的， 所以tx["list"]里面的时间戳应该是有序的，直接取中间的作为中位数，不行再算
        # print('该交易传播节点数：' + str(len(tx["list"])))
        if len(tx["list"]) % 2 == 1:
            mid_timestamp = tx["list"][len(tx["list"]) // 2]["timestamp"]
        else:
            mid_timestamp = (tx["list"][len(tx["list"]) // 2]["timestamp"] + tx["list"][len(tx["list"]) // 2 - 1][
                "timestamp"]) / 2
        k = mid_timestamp / 0.8325546111577  # 根号(-ln(0.5))
        ith = 0
        for node in tx["list"]:  # 这里的node其实就可以指一个数据包{ip，timestamp}
            index = ip_list.index(node['ip'])
            if k == 0:
                tx["weight"][index] = 1.0
            else:
                tx["weight"][index] = exp(-(node["timestamp"] * 1.0 / k) ** 2)
            if ith > N:
                break
            ith += 1
    # with open("data/res.json", 'w', encoding='utf8') as ft:
    #     ft.write(str(tx_list))

def get_true_cluster(tx_list,my_tx_list):
    """
        得到真实的交易的分类情况
    """
    true_cluster = [0] * len(tx_list)  # 创建全0列表
    for index,tx in enumerate(tx_list):
        if tx["tx_id"] in my_tx_list:
            true_cluster[index]=1
    return true_cluster


def get_index(lst=None,item=''):
    return [index for (index,value) in enumerate(lst) if value == item]


def matrix_pearson(tx_list):
    pearson = [[0 for _ in range(len(tx_list))] for _ in range(len(tx_list))]  # 皮尔逊相关系数矩阵，初始化全0
    i = 0
    for tx1 in tx_list:
        j = 0
        for tx2 in tx_list:
            pearson[i][j] = corrcoef(tx1["weight"], tx2["weight"])
            j += 1
        i = i + 1
    with open("data/pearson.json", 'w', encoding='utf8') as ft:
        ft.write(str(pearson))
    return pearson


def readList(list_filename):
    result_list = []
    with open(list_filename, 'r') as fp:
        for line in fp.readlines():
            line = line.strip('\n')
            result_list.append(line)
    return result_list


def get_addrmessage_info(listen_file):
    addrmassage_list = []
    error_number = 0  # 记录下不合法的数据行
    with open(listen_file, 'r') as fp:
        for line in fp.readlines():
            if "r:addr:" in line:
                li = re.findall(r"\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b", line)
                if len(li) != 2:
                    li = re.findall(ip6_regex, line)
                    if len(li) != 2:
                        # print(line)
                        error_number += 1
                        continue
                ip_addr = li[0]
                message_source = li[1]
                di = {"ip_addr": ip_addr,
                      "message_source": message_source}
                addrmassage_list.append(di)
    print("addr消息中不合法的数据行个数:" + str(error_number))
    return addrmassage_list

def check_ip(log_file):
    '''
    查找监听日志中的全部addr消息,形成列表返回
    :param log_file: 监听日志
    :return: 消息对列表[{'peer':xx.xx.x.x,'timestamp':xxxx, 'message':x.xx.x.x},{}]
    '''
    ip_addr_message=[]
    with open(log_file, 'r', encoding='utf8') as fp:
        for line in fp.readlines():
            # if "r:itx:" in line: # 选择有交易数据信息的行
            if "[INFO]: r:addr:" in line:
                li = re.findall(r"\b[0-9]{8,13}\b", line)
                if len(li) == 0:
                    continue
                timestamp = li[0]
                li = re.findall(r"\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b", line)
                if len(li) != 2:
                    continue
                message=li[0]
                source_ip=li[1]

                ip_addr_message.append({'peer':source_ip,'timestamp':timestamp,'addrmessage':message})
    return ip_addr_message

def check_ip_test():

    with open('../test_network/data/listen.out', 'r', encoding='utf8') as fp:
        for line in fp.readlines():
            # if "r:itx:" in line: # 选择有交易数据信息的行
            if "[INFO]: r:addr:" in line and '131.188.40.47:18333' in line:
                print(line)
if __name__ == '__main__':
    check_ip_test()